package com.colorlight.cloud.gateway.api.message.interceptor.trans.impl;


import com.colorlight.cloud.gateway.api.exception.ReflexException;
import com.colorlight.cloud.gateway.api.message.constraint.basics.ienum.EnumTrans;
import com.colorlight.cloud.gateway.api.message.interceptor.trans.TransFromProtoInterceptor;

import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.util.EnumSet;

/**
 * 基本类型不需要转化,非基本类型需要创建对,需要反射创建对象，注入属性，再通过反射注入目标中. 1.拿到目标的class——>EnumTrans 1.1根据JDK提供的{@link
 * EnumSet#allOf(Class)}创建对象 1.2根据反射注入属性:隐式使用@{@link EnumTrans#formProto(Object)} 1.3拿到原始属性 2.反射注入
 * 枚举类型 不仅需要拿出属性，还需要做出转化
 *
 * @author Demon
 * @date 25/12/2023 下午1:47
 */
public class EnumTransFromProtoInterceptor implements TransFromProtoInterceptor {
  private static final String FORM_PROTO = "formProto";

  @Override
  public Boolean isInterceptor(Class<?> aClass) {
    return Enum.class.isAssignableFrom(aClass) && EnumTrans.class.isAssignableFrom(aClass);
  }

  @Override
  public void addAttribute(
      Object transObject, Object value, Class<?> inputClass, String methodName) {
    // 原始转为可入参类型
    Object o = enumConversionObject(inputClass, value);
    Method method;
    try {
      method = transObject.getClass().getMethod(methodName, inputClass);
    } catch (NoSuchMethodException e) {
      throw new ReflexException("目标枚举类型不存在这个方法");
    }
    try {
      method.invoke(transObject, o);
    } catch (IllegalAccessException | InvocationTargetException e) {
      throw new ReflexException("目标枚举类型方法调用失败");
    }
  }

  /**
   * 根据 类型 转化属性
   *
   * <p>1.创建枚举对象 2.获取目标属性 3.反射注入枚举属性
   *
   * @param enumClass 枚举类型的class
   * @param sourceValue 原始值
   * @author Demon
   * @date 29/12/2023/上午10:05
   * @return 目标属性
   */
  public Object enumConversionObject(Class<?> enumClass, Object sourceValue) {
    // 创建枚举对象
    Enum<?> nilEnumObject = builderEnumByClass((Class<Enum>) enumClass);
    // 获取目标属性
    return setTransEnumValue(FORM_PROTO, nilEnumObject, sourceValue);
  }

  /**
   * 反射注入
   *
   * @param methodName 注入方法名 固定为 ： formProto
   * @param object 通过反射构建的对象
   * @param aClass 入参类型：从transClass 中抓出来
   * @param value 入参
   * @author Demon
   * @date 28/12/2023/下午3:30
   * @return 目标对象
   */
  private Object setTransEnumValue(String methodName, Object object, Object value) {

    Method method = null;
    try {
      method = object.getClass().getMethod(methodName, value.getClass());
    } catch (NoSuchMethodException e) {
      throw new ReflexException("获取方法失败");
    }
    Object invoke = null;
    try {
      assert method != null;
      invoke = method.invoke(object, value);
    } catch (IllegalAccessException | InvocationTargetException e) {
      throw new ReflexException("获取方法失败");
    }
    return invoke;
  }
  /**
   * 枚举类型没有反射 jdk提供类似反射得方法 根据类型可以拿到对象
   *
   * @param enumClass 枚举类型
   * @author Demon
   * @date 28/12/2023/下午5:47
   * @return 枚举对象
   */
  private Enum<?> builderEnumByClass(Class<? extends Enum> enumClass) {
    EnumSet<?> enumSet = EnumSet.allOf(enumClass);
    return enumSet.stream().findFirst().orElseThrow(NullPointerException::new);
  }
}
